/*  */
#include <math.h>
#include "cstdlib.h"

#include "../interpreter.h"


static double M_EValue = 2.7182818284590452354;   /* e */
static double M_LOG2EValue = 1.4426950408889634074;   /* log_2 e */
static double M_LOG10EValue = 0.43429448190325182765;  /* log_10 e */
static double M_LN2Value = 0.69314718055994530942;  /* log_e 2 */
static double M_LN10Value = 2.30258509299404568402;  /* log_e 10 */
static double M_PIValue = 3.14159265358979323846;  /* pi */
static double M_PI_2Value = 1.57079632679489661923;  /* pi/2 */
static double M_PI_4Value = 0.78539816339744830962;  /* pi/4 */
static double M_1_PIValue = 0.31830988618379067154;  /* 1/pi */
static double M_2_PIValue = 0.63661977236758134308;  /* 2/pi */
static double M_2_SQRTPIValue = 1.12837916709551257390;  /* 2/sqrt(pi) */
static double M_SQRT2Value = 1.41421356237309504880;  /* sqrt(2) */
static double M_SQRT1_2Value =  0.70710678118654752440;  /* 1/sqrt(2) */


void Cstdlib::MathSin(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = sin(param[0]->val->fP);
}

void Cstdlib::MathCos(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = cos(param[0]->val->fP);
}

void Cstdlib::MathTan(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = tan(param[0]->val->fP);
}

void Cstdlib::MathAsin(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = asin(param[0]->val->fP);
}

void Cstdlib::MathAcos(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = acos(param[0]->val->fP);
}

void Cstdlib::MathAtan(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = atan(param[0]->val->fP);
}

void Cstdlib::MathAtan2(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = atan2(param[0]->val->fP, param[1]->val->fP);
}

void Cstdlib::MathSinh(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = sinh(param[0]->val->fP);
}

void Cstdlib::MathCosh(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = cosh(param[0]->val->fP);
}

void Cstdlib::MathTanh(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = tanh(param[0]->val->fP);
}

void Cstdlib::MathExp(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = exp(param[0]->val->fP);
}

void Cstdlib::MathFabs(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = fabs(param[0]->val->fP);
}

void Cstdlib::MathFmod(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = fmod(param[0]->val->fP, param[1]->val->fP);
}

void Cstdlib::MathFrexp(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = frexp(param[0]->val->fP, (int *)param[1]->val->pointer);
}

void Cstdlib::MathLdexp(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = ldexp(param[0]->val->fP, param[1]->val->integer);
}

void Cstdlib::MathLog(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = log(param[0]->val->fP);
}

void Cstdlib::MathLog10(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = log10(param[0]->val->fP);
}

void Cstdlib::MathModf(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = modf(param[0]->val->fP, (double *)param[0]->val->pointer);
}

void Cstdlib::MathPow(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = pow(param[0]->val->fP, param[1]->val->fP);
}

void Cstdlib::MathSqrt(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = sqrt(param[0]->val->fP);
}

void Cstdlib::MathRound(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    /* this awkward definition of "round()" due to it being inconsistently
     * declared in math.h */
    returnValue->val->fP = ceil(param[0]->val->fP - 0.5);
}

void Cstdlib::MathCeil(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = ceil(param[0]->val->fP);
}

void Cstdlib::MathFloor(struct ParseState *parser, Value *returnValue, Value **param, int numArgs)
{
    returnValue->val->fP = floor(param[0]->val->fP);
}

/* all math.h functions */
const LibraryFunction Cstdlib::MathFunctions[] =
{
     {Cstdlib::MathAcos, "float acos(float);"},
     {Cstdlib::MathAsin, "float asin(float);"},
     {Cstdlib::MathAtan, "float atan(float);"},
     {Cstdlib::MathAtan2, "float atan2(float, float);"},
     {Cstdlib::MathCeil, "float ceil(float);"},
     {Cstdlib::MathCos, "float cos(float);"},
     {Cstdlib::MathCosh, "float cosh(float);"},
     {Cstdlib::MathExp, "float exp(float);"},
     {Cstdlib::MathFabs, "float fabs(float);"},
     {Cstdlib::MathFloor, "float floor(float);"},
     {Cstdlib::MathFmod, "float fmod(float, float);"},
     {Cstdlib::MathFrexp, "float frexp(float, int *);"},
     {Cstdlib::MathLdexp, "float ldexp(float, int);"},
     {Cstdlib::MathLog, "float log(float);"},
     {Cstdlib::MathLog10, "float log10(float);"},
     {Cstdlib::MathModf, "float modf(float, float *);"},
     {Cstdlib::MathPow, "float pow(float,float);"},
     {Cstdlib::MathRound, "float round(float);"},
     {Cstdlib::MathSin, "float sin(float);"},
     {Cstdlib::MathSinh, "float sinh(float);"},
     {Cstdlib::MathSqrt, "float sqrt(float);"},
     {Cstdlib::MathTan,  "float tan(float);"},
     {Cstdlib::MathTanh, "float tanh(float);"},
     {NULL,  NULL }
};

/* creates various system-dependent definitions */
void Cstdlib::MathSetupFunc(Interpreter *pc)
{
    (pc, NULL, "M_E", &pc->fPType,
        (AnyValue*)&M_EValue, false);
    (pc, NULL, "M_LOG2E", &pc->fPType,
        (AnyValue*)&M_LOG2EValue, false);
    (pc, NULL, "M_LOG10E", &pc->fPType,
        (AnyValue*)&M_LOG10EValue, false);
    (pc, NULL, "M_LN2", &pc->fPType,
        (AnyValue*)&M_LN2Value, false);
    (pc, NULL, "M_LN10", &pc->fPType,
        (AnyValue*)&M_LN10Value, false);
    (pc, NULL, "M_PI", &pc->fPType,
        (AnyValue*)&M_PIValue, false);
    (pc, NULL, "M_PI_2", &pc->fPType,
        (AnyValue*)&M_PI_2Value, false);
    (pc, NULL, "M_PI_4", &pc->fPType,
        (AnyValue*)&M_PI_4Value, false);
    (pc, NULL, "M_1_PI", &pc->fPType,
        (AnyValue*)&M_1_PIValue, false);
    (pc, NULL, "M_2_PI", &pc->fPType,
        (AnyValue*)&M_2_PIValue, false);
    (pc, NULL, "M_2_SQRTPI", &pc->fPType,
        (AnyValue*)&M_2_SQRTPIValue, false);
    (pc, NULL, "M_SQRT2", &pc->fPType,
        (AnyValue*)&M_SQRT2Value, false);
    (pc, NULL, "M_SQRT1_2", &pc->fPType,
        (AnyValue*)&M_SQRT1_2Value, false);
}
